home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 001 / ymodem.arc / VVRB.C < prev    next >
Text File  |  1986-05-27  |  16KB  |  772 lines

  1. #define VERSION "vvrb 1.01 12-18-85"
  2.  
  3. /*
  4.  *
  5.  *     Code fragments stolen from VMS version of UMODEM.C
  6.  *
  7.  * A program for VMS which can receive
  8.  *  files from computers running YAM or MODEM.
  9.  *  If no filename is given, YMODEM (YAM batch) protocol is assumed.
  10.  *
  11.  *  Supports the CRC option or regular checksum.
  12.  *  Received pathnames containing no lowercase letters will be changed
  13.  *  to lower case unless -u option is given.
  14.  *
  15.  *  Unless the -b (binary) option is given, 
  16.  *  ^Z (which is discarded) acts as end of file.
  17.  *
  18.  *  If the raw pathname ends in any of the extensions in Extensions,
  19.  *   or .?Q* (squeezed file), or if the first sector contains binary-like
  20.  *   data (parity bits or characters in the range 0 to 6 before ^Z is seen),
  21.  *   or if the transmitted file mode has the 0100000 but set,
  22.  *   that file will be received in binary mode anyway.
  23.  *
  24.  *
  25.  * A log of activities is appended to LOGFILE with the -v option
  26.  *
  27.  * To compile on VMS:
  28.  *        cc vvrb.c
  29.  *        cc vvmodem.c
  30.  *        link vvrb,vvmodem
  31.  *    rb :== $disk$user2:[username.subdir]vvrb.exe
  32.  *
  33.  *    Manual page is "rb.1" in the Unix version rbsb.sh file
  34.  */
  35. #define LOGFILE "rblog"
  36.  
  37. #include <stdio.h>
  38. #include <ctype.h>
  39. #include "vmodem.h"
  40.  
  41. #ifdef vms
  42. #include ssdef
  43. #include tt2def
  44. #include ttdef
  45. #define SS_NORMAL SS$_NORMAL
  46. #else
  47. #define SS_NORMAL 0
  48. #endif
  49.  
  50. /*  VMS structures  */
  51. #ifdef vms
  52. /*
  53.  *    TT_INFO structures are used for passing information about
  54.  *    the terminal.  Used in GTTY and STTY calls.
  55.  */
  56. struct    tt_info    ttys, ttysnew, ttystemp;
  57. #endif
  58.  
  59. #define OK 0
  60. #define FALSE 0
  61. #define TRUE 1
  62. #define ERROR (-1)
  63.  
  64. char *substr();
  65. FILE *fout;
  66.  
  67. char *Extensions[] = {
  68.     ".A",
  69.     ".ARC",
  70.     ".CCC",
  71.     ".CL",
  72.     ".CMD",
  73.     ".COM",
  74.     ".CRL",
  75.     ".DAT",
  76.     ".DIR",
  77.     ".EXE",
  78.     ".O",
  79.     ".OBJ",
  80.     ".OVL",
  81.     ".PAG",
  82.     ".REL",
  83.     ".SAV",
  84.     ".SUB",
  85.     ".SWP",
  86.     ".SYS",
  87.     ".TAR",
  88.     ".UTL",
  89.     ".a",
  90.     ".o",
  91.     ".tar",
  92.     ""
  93. };
  94.  
  95. /* Ward Christensen / CP/M parameters - Don't change these! */
  96. #define ENQ 005
  97. #define CAN ('X'&037)
  98. #define XOFF ('s'&037)
  99. #define XON ('q'&037)
  100. #define SOH 1
  101. #define STX 2
  102. #define EOT 4
  103. #define ACK 6
  104. #define NAK 025
  105. #define CPMEOF 032
  106. #define WANTCRC 0103    /* send C not NAK to get crc not checksum */
  107. #define TIMEOUT (-2)
  108. #define RETRYMAX 10
  109. #define WCEOT (-10)
  110. #define SECSIZ 128    /* cp/m's Magic Number record size */
  111. #define PATHLEN 257    /* ready for 4.2 bsd ? */
  112. #define KSIZE 1024    /* record size with k option */
  113. #define UNIXFILE 0x8000    /* happens to the the S_IFREG file mask bit for stat */
  114.  
  115. int Lastrx;
  116. int Crcflg;
  117. int Firstsec;
  118. int Eofseen;        /* indicates cpm eof (^Z) has been received */
  119. int totblocks;        /* total number of blocks received */
  120. int errors;
  121.  
  122. #define DEFBYTL 2000000000L    /* default rx file size */
  123. long Bytesleft;        /* number of bytes of incoming file left */
  124. long Modtime;        /* Unix style mod time for incoming file */
  125. short Filemode;        /* Unix style mode for incoming file */
  126. char Pathname[PATHLEN];
  127.  
  128. int Batch=0;
  129. int Wcsmask=0377;
  130. int MakeLCPathname=TRUE;    /* make received pathname lower case */
  131. int Verbose=0;
  132. int Quiet=0;        /* overrides logic that would otherwise set verbose */
  133. int Rxbinary=FALSE;    /* receive all files in bin mode */
  134. int Thisbinary;        /* current file is to be received in bin mode */
  135. int Blklen;        /* record length of received packets */
  136. char secbuf[KSIZE];
  137. char linbuf[KSIZE];
  138. int Lleft=0;        /* number of characters in linbuf */
  139.  
  140. unsigned short updcrc();
  141.  
  142. main(argc, argv)
  143. char *argv[];
  144. {
  145.     register char *cp;
  146.     register npats;
  147.     char **patts;
  148.     int exitcode;
  149.  
  150.     setbuf(stderr, NULL);
  151.     npats = 0;
  152.     while (--argc) {
  153.         cp = *++argv;
  154.         if (*cp == '-') {
  155.             while( *++cp) {
  156.                 switch(*cp) {
  157.                 case '7':
  158.                     Wcsmask = 0177;
  159.                 case 'b':
  160.                     Rxbinary=TRUE; break;
  161.                 case 'k':
  162.                 case 'c':
  163.                     Crcflg=TRUE; break;
  164.                 case 'q':
  165.                     Quiet=TRUE; Verbose=0; break;
  166.                 case 'u':
  167.                     MakeLCPathname=FALSE; break;
  168.                 case 'v':
  169.                     ++Verbose; break;
  170.                 default:
  171.                     usage();
  172.                 }
  173.             }
  174.         }
  175.         else if ( !npats && argc>0) {
  176.             if (argv[0][0]) {
  177.                 npats=argc;
  178.                 patts=argv;
  179.             }
  180.         }
  181.     }
  182.     if (npats > 1)
  183.         usage();
  184.     if (Verbose) {
  185.         if (freopen(LOGFILE, "a", stderr)==NULL) {
  186.             printf("Can't open log file %s\n",LOGFILE);
  187.             exit(SS_NORMAL);
  188.         }
  189.         setbuf(stderr, NULL);
  190.     }
  191.     setmodes();
  192.  
  193.     if (wcreceive(npats, patts)==ERROR) {
  194.         exitcode=0200;
  195.         canit();
  196.     }
  197.     restoremodes(FALSE);
  198.     if (exitcode != 0)    /* bellow again with all thy might. */
  199.         canit();
  200.     exit(SS_NORMAL);
  201. }
  202.  
  203.  
  204. usage()
  205. {
  206.     fprintf(stderr,"rb %s by Chuck Forsberg\n", VERSION);
  207.     fprintf(stderr,"Usage:    rb [-buv]\n\tor rb [-bcuv] file\n");
  208.     exit(SS_NORMAL);
  209. }
  210.  
  211. wcreceive(argc, argp)
  212. char **argp;
  213. {
  214.     if (Batch || argc==0) {
  215.         Crcflg=(Wcsmask==0377);
  216.         fprintf(stderr, "rb: ready ");
  217.         for (;;) {
  218.             totblocks=0;
  219.             if (wcrxpn(secbuf)== ERROR)
  220.                 goto fubar;
  221.             if (secbuf[0]==0)
  222.                 return OK;
  223.             if (procheader(secbuf) == ERROR)
  224.                 goto fubar;
  225.             if (wcrx()==ERROR)
  226.                 goto fubar;
  227.         }
  228.     } else {
  229.         totblocks=0; Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
  230.  
  231.         strcpy(Pathname, *argp);
  232.         if (fopen(*argp, "r") != NULL) {
  233.             fprintf(stderr, "rb: %s exists\n", Pathname);
  234.             goto fubar;
  235.         }
  236.         fprintf(stderr, "\nrb: ready to receive %s ", Pathname);
  237.         if ((fout=fopen(Pathname, "w")) == NULL)
  238.             return ERROR;
  239.         if (wcrx()==ERROR)
  240.             goto fubar;
  241.     }
  242.     return OK;
  243. fubar:
  244.     canit();
  245.     if (fout)
  246.         fclose(fout);
  247.     return ERROR;
  248. }
  249.  
  250.  
  251. /*
  252.  * Fetch a pathname from the other end as a C ctyle ASCIZ string.
  253.  * Length is indeterminate as long as less than Blklen
  254.  * a null string represents no more files
  255.  */
  256. wcrxpn(rpn)
  257. char *rpn;    /* receive a pathname */
  258. {
  259.     register c;
  260.  
  261. et_tu:
  262.     Firstsec=TRUE;
  263.     sendline(Crcflg?WANTCRC:NAK);
  264.     while ((c = wcgetsec(rpn, 100)) != 0) {
  265.         log( "Pathname fetch returned %d\n", c);
  266.         if (c == WCEOT) {
  267.             sendline(ACK); readline(1); goto et_tu;
  268.         }
  269.         return ERROR;
  270.     }
  271.     sendline(ACK);
  272.     return OK;
  273. }
  274.  
  275. /*
  276.  * Adapted from CMODEM13.C, written by
  277.  * Jack M. Wierda and Roderick W. Hart
  278.  */
  279.  
  280. wcrx()
  281. {
  282.     register int sectnum, sectcurr;
  283.     register char sendchar;
  284.     register char *p;
  285.     int cblklen;            /* bytes to dump this block */
  286.     long timep[2];
  287.  
  288.     Firstsec=TRUE;sectnum=0; Eofseen=FALSE;
  289.     sendchar=Crcflg?WANTCRC:NAK;
  290.  
  291.     for (;;) {
  292.         sendline(sendchar);    /* send it now, we're ready! */
  293.         sectcurr=wcgetsec(secbuf, (sectnum&0177)?50:130);
  294.         report(sectcurr);
  295.         if (sectcurr==(sectnum+1 &Wcsmask)) {
  296.  
  297.             if (sectnum==0 && !Thisbinary)
  298.                 for (p=secbuf,sectcurr=Blklen;
  299.                 *p != 032 && --sectcurr>=0; ++p)
  300.                     if (*p < 07 || (*p & 0200)) {
  301.                         Thisbinary++;
  302.                         if (Verbose)
  303.                             fprintf(stderr, "Changed to BIN\n");
  304.                         break;
  305.                     }
  306.             sectnum++;
  307.             cblklen = Bytesleft>Blklen ? Blklen:Bytesleft;
  308.             if (putsec(secbuf, cblklen)==ERROR)
  309.                 return ERROR;
  310.             if ((Bytesleft-=cblklen) < 0)
  311.                 Bytesleft = 0;
  312.             sendchar=ACK;
  313.         }
  314.         else if (sectcurr==(sectnum&Wcsmask)) {
  315.             log( "Received dup Sector\n");
  316.             sendchar=ACK;
  317.         }
  318.         else if (sectcurr==WCEOT) {
  319.             if (fclose(fout)==ERROR) {
  320.                 canit();
  321.                 fprintf(stderr, "file close ERROR\n");
  322.                 return ERROR;
  323.             }
  324.             if (Modtime) {
  325.                 timep[0] = time(NULL);
  326.                 timep[1] = Modtime;
  327. /*
  328.                 utime(Pathname, timep);
  329. */
  330.             }
  331.             if (Filemode)
  332.                 chmod(Pathname, (07777 & Filemode));
  333.             sendline(ACK);
  334.             return OK;
  335.         }
  336.         else if (sectcurr==ERROR)
  337.             return ERROR;
  338.         else {
  339.             log( "Sync Error\n");
  340.             return ERROR;
  341.         }
  342.     }
  343. }
  344.  
  345. /*
  346.  * wcgetsec fetches a Ward Christensen type sector.
  347.  * Returns sector number encountered or ERROR if valid sector not received,
  348.  * or CAN CAN received
  349.  * or WCEOT if eot sector
  350.  * time is timeout for first char, set to 4 seconds thereafter
  351.  ***************** NO ACK IS SENT IF SECTOR IS RECEIVED OK **************
  352.  *    (Caller must do that when he is good and ready to get next sector)
  353.  */
  354.  
  355. wcgetsec(rxbuf, maxtime)
  356. char *rxbuf;
  357. int maxtime;
  358. {
  359.     register checksum, wcj, firstch;
  360.     register unsigned short oldcrc;
  361.     register char *p;
  362.     int sectcurr;
  363.  
  364.     for (Lastrx=errors=0; errors<RETRYMAX; errors++) {
  365.  
  366.         if ((firstch=readline(maxtime))==STX) {
  367.             Blklen=KSIZE; goto get2;
  368.         }
  369.         if (firstch==SOH) {
  370.             Blklen=SECSIZ;
  371. get2:
  372.             sectcurr=readline(5);
  373.             if ((sectcurr+(oldcrc=readline(5)))==Wcsmask) {
  374.                 oldcrc=checksum=0;
  375.                 for (p=rxbuf, wcj=Blklen; wcj; wcj -= 128) {
  376.                     if (raw_read(128,p,7) == SS$_TIMEOUT) {
  377.                         firstch=TIMEOUT; goto bilge;
  378.                     }
  379.                     p += 128;
  380.                 }
  381.                 for (p=rxbuf, wcj=Blklen; --wcj>=0; ) {
  382.                     firstch = *p++ & Wcsmask;
  383.                     oldcrc=updcrc(firstch, oldcrc);
  384.                     checksum += (firstch);
  385.                 }
  386.                 if ((firstch=readline(5)) < 0)
  387.                     goto bilge;
  388.                 if (Crcflg) {
  389.                     oldcrc=updcrc(firstch, oldcrc);
  390.                     if ((firstch=readline(5)) < 0)
  391.                         goto bilge;
  392.                     oldcrc=updcrc(firstch, oldcrc);
  393.                     if (oldcrc)
  394.                         log("CRC=0%o\n", oldcrc);
  395.                     else {
  396.                         Firstsec=FALSE;
  397.                         return sectcurr;
  398.                     }
  399.                 }
  400.                 else if (((checksum-firstch)&Wcsmask)==0) {
  401.                     Firstsec=FALSE;
  402.                     return sectcurr;
  403.                 }
  404.                 else
  405.                     log( "Checksum Error\n");
  406.             }
  407.             else
  408.                 log("Sector number garbled 0%o 0%o\n",
  409.                 sectcurr, oldcrc);
  410.         }
  411.         /* make sure eot really is eot and not just mixmash */
  412.         else if (firstch==EOT && Lleft==0)
  413.             return WCEOT;
  414.         else if (firstch==CAN) {
  415.             if (Lastrx==CAN) {
  416.                 log( "Sender CANcelled\n");
  417.                 return ERROR;
  418.             } else {
  419.                 Lastrx=CAN;
  420.                 continue;
  421.             }
  422.         }
  423.         else if (firstch==TIMEOUT) {
  424.             if (Firstsec)
  425.                 goto humbug;
  426. bilge:
  427.             log( "Timeout\n");
  428.         }
  429.         else
  430.             log( "Got 0%o sector header\n", firstch);
  431.  
  432. humbug:
  433.         Lastrx=0;
  434.         if (firstch != TIMEOUT)
  435.             junkpacket();
  436.         if (Firstsec)
  437.             sendline(Crcflg?WANTCRC:NAK);
  438.         else {
  439.             maxtime=40; sendline(NAK);
  440.         }
  441.     }
  442.     /* try to stop the bubble machine. */
  443.     canit();
  444.     return ERROR;
  445. }
  446.  
  447.  
  448. /* update CRC */
  449. unsigned short
  450. updcrc(c, crc)
  451. register c;
  452. register unsigned crc;
  453. {
  454.     register count;
  455.  
  456.     for (count=8; --count>=0;) {
  457.         if (crc & 0x8000) {
  458.             crc <<= 1;
  459.             crc += (((c<<=1) & 0400)  !=  0);
  460.             crc ^= 0x1021;
  461.         }
  462.         else {
  463.             crc <<= 1;
  464.             crc += (((c<<=1) & 0400)  !=  0);
  465.         }
  466.     }
  467.     return crc;    
  468. }
  469.  
  470. /*
  471.  * process incoming header
  472.  */
  473. procheader(name)
  474. char *name;
  475. {
  476.     register char *openmode, *p, **pp;
  477.  
  478.     /* set default parameters */
  479.     openmode = "w"; Thisbinary=Rxbinary;
  480.     Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
  481.  
  482.     p = name + 1 + strlen(name);
  483.     if (*p) {    /* file coming from Unix type system */
  484.         sscanf(p, "%ld%lo%o", &Bytesleft, &Modtime, &Filemode);
  485.         if (Filemode & UNIXFILE)
  486.             ++Thisbinary;
  487.         if (Verbose) {
  488.             fprintf(stderr,  "Incoming: %s %ld %lo %o\n",
  489.             name, Bytesleft, Modtime, Filemode);
  490.         }
  491.     }
  492.     else {        /* File coming from CP/M type system */
  493.         for (p=name; *p; ++p)        /* change / to _ */
  494.             if ( *p == '/')
  495.                 *p = '_';
  496.  
  497.         if ( *--p == '.')        /* zap trailing period */
  498.             *p = 0;
  499.     }
  500.  
  501.     /* scan for extensions that signify a binary file */
  502.     if (p=substr(name, "."))
  503.         for (pp=Extensions; **pp; ++pp)
  504.             if (strcmp(p, *pp)==0) {
  505.                 Thisbinary=TRUE; break;
  506.             }
  507.  
  508.     /* scan for files which should be appended */
  509.     if ( !Thisbinary
  510.     && (substr(name, ".TXT")
  511.     || substr(name, ".txt")
  512.     || substr(name, ".MSG")))
  513.         openmode = "a";
  514.     if (MakeLCPathname && !IsAnyLower(name))
  515.         uncaps(name);
  516.     strcpy(Pathname, name);
  517.     if (Verbose) {
  518.         fprintf(stderr,  "Receiving %s %s %s\n",
  519.         name, Thisbinary?"BIN":"ASCII", openmode);
  520.     }
  521.     if ((fout=fopen(name, openmode)) == NULL)
  522.         return ERROR;
  523.     return OK;
  524. }
  525.  
  526. /* make string s lower case */
  527. uncaps(s)
  528. register char *s;
  529. {
  530.     for ( ; *s; ++s)
  531.         if (isupper(*s))
  532.             *s = tolower(*s);
  533. }
  534.  
  535.  
  536. /*
  537.  * IsAnyLower returns TRUE if string s has lower case letters.
  538.  */
  539. IsAnyLower(s)
  540. register char *s;
  541. {
  542.     for ( ; *s; ++s)
  543.         if (islower(*s))
  544.             return TRUE;
  545.     return FALSE;
  546. }
  547. /*
  548.  * putsec writes the n characters of buf to receive file fout.
  549.  *  If not in binary mode, carriage returns, and all characters
  550.  *  starting with CPMEOF are discarded.
  551.  */
  552. putsec(buf, n)
  553. char *buf;
  554. register n;
  555. {
  556.     register char *p;
  557.  
  558.     ++totblocks;
  559.     if (Thisbinary)
  560.     {
  561.         for (p=buf; --n>=0; )
  562.             putc( *p++, fout);
  563.     }
  564.     else {
  565.         if (Eofseen)
  566.             return OK;
  567.         for (p=buf; --n>=0; ++p ) {
  568. /*
  569.             if ( *p == '\r')
  570.                 continue;
  571. */
  572.             if (*p == CPMEOF) {
  573.                 Eofseen=TRUE; return OK;
  574.             }
  575.             putc(*p ,fout);
  576.         }
  577.     }
  578.     return OK;
  579. }
  580.  
  581.  
  582. /*
  583.  * substr(string, token) searches for token in string s
  584.  * returns pointer to token within string if found, NULL otherwise
  585.  */
  586. char *
  587. substr(s, t)
  588. register char *s,*t;
  589. {
  590.     register char *ss,*tt;
  591.     /* search for first char of token */
  592.     for (ss=s; *s; s++)
  593.         if (*s == *t)
  594.             /* compare token with substring */
  595.             for (ss=s,tt=t; ;) {
  596.                 if (*tt == 0)
  597.                     return s;
  598.                 if (*ss++ != *tt++)
  599.                     break;
  600.             }
  601.     return NULL;
  602. }
  603.  
  604. /*VARARGS1*/
  605. log(s,p,u)
  606. char *s, *p, *u;
  607. {
  608.     if (!Verbose)
  609.         return;
  610.     fprintf(stderr, "error %d: ", errors);
  611.     fprintf(stderr, s, p, u);
  612. }
  613.  
  614. /* send 10 CAN's to try to get the other end to shut up */
  615. canit()
  616. {
  617.     register n;
  618.     for (n=10; --n>=0; )
  619.         sendline(CAN);
  620. }
  621.  
  622. #ifdef REGULUS
  623. /*
  624.  * copies count bytes from s to d
  625.  * (No structure assignment in Regulus C compiler)
  626.  */
  627.  
  628. movmem(s, d, count)
  629. register char *s, *d;
  630. register count;
  631. {
  632.     while (--count >= 0)
  633.         *d++ = *s++;
  634. }
  635. #endif
  636.  
  637.  
  638. report(sct)
  639. int sct;
  640. {
  641.     if (Verbose>1)
  642.         fprintf(stderr,"%03d%c",sct,sct%10? ' ' : '\r');
  643. }
  644.  
  645. /* set tty modes for vvrb transfers */
  646. setmodes()
  647. {
  648. /*  Device characteristics for VMS  */
  649. #ifdef vms
  650.     int    *iptr, parameters;
  651.  
  652. /*
  653.  *    Get current terminal parameters.
  654.  */
  655.     if (gtty(&ttys) != SS$_NORMAL)
  656.         error("SETMODES:  error return from GTTY (1)", FALSE);
  657.     if (gtty(&ttysnew) != SS$_NORMAL)
  658.         error("SETMODES:  error return from GTTY (2)", FALSE);
  659.  
  660. /*
  661.  *    Set new terminal parameters.
  662.  *    Note that there are three bytes of terminal characteristics,
  663.  *    so we should make sure the fourth byte of the integer is unchanged.
  664.  */
  665.     iptr    = &(ttysnew.dev_characteristics.bcharacteristics);
  666.     parameters    = *iptr;
  667.  
  668.     parameters    &= ~TT$M_ESCAPE;        /*  ESCAPE   OFF  */
  669.     parameters    &= ~TT$M_HOSTSYNC;        /*  HOSTSYNC OFF  */
  670.     parameters    |=  TT$M_NOECHO;        /*  NOECHO   ON   */
  671.     parameters    |=  TT$M_PASSALL;        /*  PASSALL  ON   */
  672.     parameters    &= ~TT$M_READSYNC;        /*  READSYNC OFF  */
  673.     parameters    &= ~TT$M_TTSYNC;        /*  TTSYNC   OFF  */
  674.     parameters    &= ~TT$M_WRAP;            /*  WRAP     OFF  */
  675.     parameters    |= TT$M_EIGHTBIT;        /*  EIGHTBIT ON   */
  676.  
  677.     *iptr        = parameters;
  678.  
  679.     if (stty(&ttysnew) != SS_NORMAL)
  680.         error("SETMODES:  error return from STTY", TRUE);
  681. #endif
  682. }
  683.  
  684.  
  685.  
  686. /* restore normal tty modes */
  687. restoremodes(errcall)
  688. int errcall;
  689. {
  690. /*  Device characteristic restoration for VMS  */
  691. #ifdef vms
  692.     if (stty(&ttys) != SS_NORMAL)        /*  Restore original modes  */
  693.         {
  694.         if (!errcall)
  695.             error("Error restoring original terminal params.",
  696.                                     FALSE);
  697.         else
  698.             {
  699.             printf("vvrb/RESTOREMODES:  ");
  700.             printf("Error restoring original terminal params.\n");
  701.             }
  702.         }
  703. #endif
  704. }
  705.  
  706. /*
  707.     BBUFSIZ  - 128 or 1024 etc.
  708.     raw_read(BBUFSIZ + 7, inbuf, 5 + 3 * (BBUFSIZ + 6));
  709. */
  710.  
  711.  
  712.  
  713.  
  714. /* get a byte from data stream -- timeout if "dseconds" elapses */
  715. /*    NOTE, however, that this function returns an INT, not a BYTE!!!  */
  716. readline(dseconds)
  717. {
  718.     int seconds;
  719.     int    c;
  720.  
  721.     seconds = dseconds/10;
  722.     if (seconds < 5)
  723.         seconds = 5;
  724. #ifdef vms
  725.     c    = raw_read(1, &c, seconds);
  726.  
  727.     if (c == SS$_TIMEOUT)
  728.         return(TIMEOUT);
  729.  
  730.     return(c & 0377);  /* return the char */
  731. #endif
  732. }
  733.  
  734. /* junkpacket gets the line cleared */
  735. junkpacket()
  736. {
  737.     int    c;
  738.  
  739. #ifdef vms
  740.     for (;;) {
  741.         c    = raw_read(1, &c, 1);
  742.  
  743.         if (c == SS$_TIMEOUT)
  744.             return;
  745.         }
  746. #endif
  747. }
  748.  
  749. /* send a byte to data stream */
  750. sendline(data)
  751. {
  752.     char    dataout;
  753.  
  754.     dataout    = data;
  755. #ifdef vms
  756.     raw_write(dataout);
  757. #endif
  758.  
  759. }
  760.  
  761.  
  762. /* print error message and exit; if mode == TRUE, restore normal tty modes */
  763. error(msg, mode)
  764. char *msg;
  765. int mode;
  766. {
  767.     if (mode)
  768.         restoremodes(TRUE);  /* put back normal tty modes */
  769.     printf("vvrb:  %s\n", msg);
  770.     exit(SS_NORMAL);
  771. }
  772.